#include "FIRManager.h"
#include <cassert>
#include "firplayer.h"

#define UNREFERENCED_PARAMETER(m) (m)

// the unique instance of class FIRManager
FIRManager FIRManager::instance;

Byte FIRManager::matrix[15][15] = {0};

void FIRManager::Init()
{
    started = false;
    order = kPlayerBlack;
}

FIRManager& FIRManager::Instance()
{
    return instance;
}

void FIRManager::StartGame( FIRPlayer * p1, FIRPlayer* p2 )
{	
    player1 = p1;
    player2 = p2;

    started = true;

    last_move.x = 0xffff;
    last_move.y = 0xffff;

    game_thread = CreateThread(
        NULL,		// default security attributes
        0,			// use default stack size
        GameLoop,	// thread function name
        this,		// argument of thread
        0,			// use default creation flags
        &thread_id);		// do not get the thread identifier

}


void FIRManager::GameOver()
{
    ::CloseHandle(game_thread);
    game_thread = 0;
    started = false;
    delete player1;
    delete player2;
    player1 = player2 = 0;
    memset(matrix, 0, sizeof matrix);
    if (kPlayerBlack == order) {
        FIRRenderer::Instance().MessageBox(L"Winner is Black!", L"Game Over", MB_OK);
    } else {
        FIRRenderer::Instance().MessageBox(L"Winner is White!", L"Game Over", MB_OK);
    }
}

void FIRManager::EndCurrentGame()
{
    if (game_thread) 
        assert(::TerminateThread(game_thread, 0));
    if (player1)
        delete player1;
    if (player2)
        delete player2;
    player1 = player2 = 0;
    started = false;
    order = kPlayerBlack;
    memset(matrix, 0, sizeof matrix);
}

DWORD WINAPI FIRManager::GameLoop( LPVOID lpParam )
{
    UNREFERENCED_PARAMETER(lpParam);
    while (FIRManager::Instance().Next());
    FIRManager::Instance().GameOver();
    return 0;
}

bool FIRManager::Next()
{
    // get current player
    FIRPlayer * current_player = (order == kPlayerBlack ? player1 : player2);

    // generate a move
    FIRMove move = current_player->GenerateMove(matrix);

    // update chess matrix
    matrix[move.y][move.x] = static_cast<Byte>(current_player->GetChessType());

    if (IsGameOver(move)) {
        return false;
    }

    // update the lastmove
    last_move = move;

    // the new order
    order = (order == kPlayerBlack ? 
        player2->GetChessType() : player1->GetChessType());

    return true;
}

bool FIRManager::IsGameOver( FIRMove move )
{
    int player = matrix[move.y][move.x];

    int count = 0;

    // Check horizontal 
    int x = move.x;
    while(x < 15)
    {
        if (player == matrix[move.y][x])
            count++;
        else
            break;
        x++;
    }
    x = move.x;
    while(x >= 0)
    {
        if (player == matrix[move.y][x])
            count++;
        else
            break;
        x--;
    }
    count--;
    if(5 <= count)
        return true;


    // Check vertical 
    count = 0;
    int y = move.y;
    while(y < 15)
    {
        if (player == matrix[y][move.x])
            count++;
        else
            break;
        y++;
    }
    y = move.y;
    while(y >= 0)
    {
        if (player == matrix[y][move.x])
            count++;
        else
            break;
        y--;
    }
    count--;
    if(5 <= count)
        return true;

    // Check 45 degrees counterclockwise
    count = 0;
    x = move.x;
    y = move.y;

    while(x < 15 && y < 15)
    {
        if (player == matrix[y][x])
            count++;
        else
            break;
        x++;
        y++;
    }

    x = move.x;
    y = move.y;
    while(x >= 0 && y >= 0)
    {
        if (player == matrix[y][x])
            count++;
        else
            break;
        x--;
        y--;
    }
    count--;
    if(5 <= count)
        return true;

    // Check 45 degrees clockwise
    count = 0;
    x = move.x;
    y = move.y;

    while(x < 15 && y >= 0)
    {
        if (player == matrix[y][x])
            count++;
        else
            break;
        x++;
        y--;
    }

    x = move.x;
    y = move.y;
    while(x >= 0 && y < 15)
    {
        if (player == matrix[y][x])
            count++;
        else
            break;
        x--;
        y++;
    }
    count--;
    if(5 <= count)
        return true;

    return false;
}

FIRChessType FIRManager::GetCurrentOrder()
{
    return order;
}

DWORD FIRManager::GetThreadId()
{
    return thread_id;
}

HANDLE FIRManager::GetThreadHandler()
{
    return game_thread;
}

FIRMove FIRManager::GetLastMove() const
{
    return last_move;
}
